﻿#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>

using namespace std;
//委托构造函数
//class Example
//{
//public:
//	Example(int x,int y)
//		:_x(x), _y(y)
//	{
//		cout<<"目标构造函数"<<endl;
//	}
//	Example(int a)
//		:Example(a, 0)
//	{
//		cout << "委托构造函数" << endl;
//	}
//private:
//	int _x;
//	int _y;
//};
////不可以这样
//class Time
//{
//public:
//	Time(int hour, int minute)
//		:_hour(hour), _minute(minute)
//	{
//	}
//	Time(int hour, int minute,int second)
//		:Time(hour, minute), _second(second)//这里会报错
//		//委托构造函数仅为成员初始值设定项
//	{
//
//	}
//
//private:
//	int _hour;
//	int _minute;
//	int _second;
//};
//继承构造函数
class Base {
public:
	Base(int x, double d)
		:_x(x)
		, _d(d)
	{
	}

	Base(int x)
		:_x(x)
	{
	}

	Base(double d)
		:_x(d)
	{
	}

protected:
	int _x = 0;
	double _d = 0;
};
// 传统的派生类实现构造
//class Derived : public Base {
//public:
//	Derived(int x) : Base(x) {}
//	Derived(double d) : Base(d) {}
//	Derived(int x, double d) : Base(x, d) {}
//};

 /*C++11继承基类的所有构造函数
 1、没有成员变量的派生类
 2、成员变量都有缺省值，并且我们就想用这个缺省值初始化*/

class Derived : public Base {
public:
	using Base::Base;

	protected:
		int _i;
		string _s;
};
void test3()
{
	Derived d1(1);
	Derived d2(1.1);
	Derived d3(2, 2.2);
}
//lambda表达式
void test4()
{
	//一个简单的lambda表达式
	auto add1 = [](int x, int y)->int {return x + y; };
	cout << add1(1,2) << endl;
	auto add2 = [](int x, int y) {return x + y; };
	cout << add2(1, 2) << endl;
	// 1、捕捉为空也不能省略
	// 2、参数为空可以省略
	// 3、返回值可以省略，可以通过返回对象⾃动推导
	// 4、函数体不能省略
}
void test5()
{
	auto func1 = []
		{
			cout << "hello shihua" << endl;
			return 0;
		};
	func1();
	int a = 0, b = 1;
	cout <<"比较前>" << a << ":" << b << endl;
	auto swap1 = [](int& x, int& y)
		{
			int tmp = x;
			x = y;
			y = tmp;
		};
	swap1(a, b);
	cout << "比较后>" << a << ":" << b << endl;
}
//lambda表达式的应用：商品排序
struct Goods
{
	string _names;//商品名称
	double _price;//商品价格
	int _count;//商品数量
	double _evaluate;//评价
	Goods(string name, double price, int count, double evaluate)
		:_names(name), _price(price)
		, _count(count), _evaluate(evaluate)
	{

	}
};
// 仿函数小于比较 - 修正类型处理
struct ComparePriceLess
{
	bool operator()(const Goods& gl, const Goods& gr) const
	{
		// 明确处理double类型的比较
		return gl._price < gr._price;
	}
};

// 仿函数大于比较 - 修正类型处理
struct ComparePriceGreater
{
	bool operator()(const Goods& gl, const Goods& gr) const
	{
		// 明确处理double类型的比较
		return gl._price > gr._price;
	}
};
void Print(vector<Goods>& VG)
{
	for (auto& vg : VG)
	{
		cout << vg._names << ":" << vg._price << ":" << vg._count << ":" << vg._evaluate << endl;
	}
	cout << "*********************************************" << endl;
}
//仿函数排序
void test6()
{
	vector<Goods> goods =
	{ {"苹果",1.0,10,2.3},{"香蕉",2.0,20,3.5},{"橘子",3.0,30,4.7},
	{"可乐",4.0,40,5.9},{"巧克力饼干",5.0,50,7.1},{"奶油面包",6.0,60,8.3},
	{"橘汁",3.0,70,9.5},{"雪碧",2.0,80,10.7},{"牛奶",4.0,90,11.9} };
	// 类似这样的场景，我们实现仿函数对象或者函数指针⽀持商品中
// 不同项的⽐较，相对还是⽐较⿇烦的，那么这⾥lambda就很好⽤了
	Print(goods);
	sort(goods.begin(), goods.end(), ComparePriceLess());
	Print(goods);
	sort(goods.begin(), goods.end(), ComparePriceGreater());
	Print(goods);
}
//lambda表达式排序
void test7()
{
	vector<Goods> goods =
	{ {"苹果",1.0,10,2.3},{"香蕉",2.0,20,3.5},{"橘子",3.0,30,4.7},
	{"可乐",4.0,40,5.9},{"巧克力饼干",5.0,50,7.1},{"奶油面包",6.0,60,8.3},
	{"橘汁",3.0,70,9.5},{"雪碧",2.0,80,10.7},{"牛奶",4.0,90,11.9} };
	Print(goods);
	sort(goods.begin(), goods.end(), [](const Goods& g1, const Goods& g2) {
		return g1._price < g2._price;
		});
	Print(goods);
	sort(goods.begin(), goods.end(), [](const Goods& g1, const Goods& g2) {
		return g1._price > g2._price;
		});
	Print(goods);
	sort(goods.begin(), goods.end(), [](const Goods& g1, const Goods& g2) {
		return g1._evaluate < g2._evaluate;
		});
	Print(goods);
	sort(goods.begin(), goods.end(), [](const Goods& g1, const Goods& g2) {
		return g1._evaluate > g2._evaluate;
		});
	Print(goods);
}

//捕获列表
int x = 0;
// 捕捉列表必须为空，因为全局变量不⽤捕捉就可以⽤，没有可被捕捉的变量
auto func0 = []()
	{
		x++;
	};
void test8()
{
	// 只能⽤当前lambda局部域和捕捉的对象和全局对象
	int a = 0, b = 1, c = 2, d = 3;
	auto func1 = [a, &b]
		{
			// 值捕捉的变量不能修改，引⽤捕捉的变量可以修改
			//a++;
			b++;
			int ret = a + b;
			return ret;
		};
	cout << func1() << endl;
}
void test9()
{
	int a = 0, b = 1, c = 2, d = 3;
	// 隐式值捕捉
	// ⽤了哪些变量就捕捉哪些变量
	auto func2 = [=]
		{
			int ret = a + b + c;
			return ret;
		};
	cout << func2() << endl;
	// 隐式引⽤捕捉
// ⽤了哪些变量就捕捉哪些变量
	auto func3 = [&]
		{
			a++;
			c++;
			d++;
		};
	func3();
	cout << a << ":" << b << ":" << c << ":" << d << endl;
}
void test10()
{
	int a = 0, b = 1, c = 2, d = 3;
	// 混合捕捉1
	auto func4 = [&, a, b]		{
			//a++;			//b++;
			c++;			d++;			return a + b + c + d;		};	func4();	cout << a << " " << b << " " << c << " " << d << endl;
	// 混合捕捉2
	auto func5 = [=, &a, &b]		{			a++;			b++;
			/*c++;			d++;*/
			return a + b + c + d;		};	func5();	cout << a << " " << b << " " << c << " " << d << endl;
}
void test11()
{
	int a = 0, b = 1, c = 2, d = 3;
	// 局部的静态和全局变量不能捕捉，也不需要捕捉
	static int m = 0;	auto func6 = []		{			int ret = x + m;			return ret;		};
	// 传值捕捉本质是⼀种拷⻉,并且被const修饰了	// mutable相当于去掉const属性，可以修改了	// 但是修改了不会影响外⾯被捕捉的值，因为是⼀种拷⻉
	auto func7 = [=]()mutable		{			a++;			b++;			c++;
			d++;			return a + b + c + d;		};	cout << func7() << endl;	cout << a << " " << b << " " << c << " " << d << endl;

}
//lambda表达式的原理
class Rate{	public :	Rate(double rate)		: _rate(rate)	{	}	double operator()(double money, int year)	{		return money * _rate * year;	}private:	double _rate;};
void test12()
{
	double rate = 0.49;
	// lambda
	auto r2 = [rate](double money, int year) {		return money * rate * year;		};
	// 函数对象
	Rate r1(rate);	r1(10000, 2);	r2(10000, 2);	auto func1 = [] {		cout << "hello world" << endl;		};	func1();
}
int main()
{
	/*Example e(10);
	Example e2(10,20);*/
	//test3();
	//test4();
	//test5();
	//test6();
	//test7();
	//func0();
	//test8();
	//test9();
	//test10();
	//test11();
	test12();
	return 0;
}